package com.yc.cinema;

import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.*;
import org.springframework.stereotype.Component;

import java.util.Arrays;

@Component
@Aspect // 切面注解
public class MyAspect {

    // 在业务方法执行前打印方法名和参数列表
    // 1. 构造函数注入, 2. set注入,  3.接口注入
    // 前置增强方法
    // 拦截action包下所有类的所有方法, ..表示参数不限
    @Before("execution(* com.yc.cinema.web.*.*(..))")
    public void logger(JoinPoint jp) { // 3.接口注入 连接到对象
        System.out.println("方法签名: " + jp.getSignature());
        System.out.println("参数列表: " + Arrays.toString(jp.getArgs()));
        System.out.println("bean对象: " + jp.getTarget());
    }

    // 切点方法
    @Pointcut("execution(* com.yc.cinema.web.*.*(..))")
    public void pointcut1() {
    }

    // 引用切点方法的表达式
    @Before("pointcut1()")
    public void before(JoinPoint jp) { // 3.接口注入 连接到对象
        System.out.println("before: 方法签名: " + jp.getSignature());
    }

    @After("pointcut1()")
    public void after(JoinPoint jp) { // 3.接口注入 连接到对象
        System.out.println("after: 方法签名: " + jp.getSignature());
    }

    // 业务方法正常执行并且返回结果, 返回的结果, spring通过方法参数注入
    @AfterReturning(value = "pointcut1()", returning = "ret")
    public void afterReturning(JoinPoint jp, Object ret) { // 3.接口注入 连接到对象
        System.out.println("afterReturning: 方法签名: " + jp.getSignature());
        System.out.println("afterReturning: 返回结果: " + ret);
    }

    // 当业务方法出现异常时, 执行的增强
    @AfterThrowing(value = "pointcut1()", throwing = "e")
    public void afterThrowing(JoinPoint jp, Exception e) { // 3.接口注入 连接到对象
        System.out.println("AfterThrowing: 方法签名: " + jp.getSignature());
        System.out.println("AfterThrowing: 异常对象: " + e);
    }

    @Pointcut("execution(* com..biz.*.*(..))")
    public void pointCut2(){}

    // 性能监控
    @Around("pointCut2()")
    // 环绕增强方法的返回值就是业务方法的返回值
    public Object around(ProceedingJoinPoint pjp){
        // 环绕增强特有连接点对象 ProceedingJoinPoint
        // 业务方法需要手工调用
        long time1 = System.currentTimeMillis();
        Object ret = null;
        try {
            // 执行业务方法
            ret = pjp.proceed();
        } catch (Throwable throwable) {
            throwable.printStackTrace();
        }
        long time2 = System.currentTimeMillis();
        long time = time2 - time1;
        System.out.println(pjp.getSignature() + "执行了" + time + "毫秒");
        // 返回业务方法的执行结果
        return ret;
    }
}
